;;;; bcgreek-cli.lisp

(in-package #:bcgreek/cli)

(defparameter *cli-options* '((("final-sigma" #\s) :type boolean :optional t :documentation "Do not automatically convert S into final sigma")
                              (("file" #\f) :type string :optional t :documentation "Input file; if this option is missing, standard input is used")
                              (("string" #\x) :type string :optional t :documentation "Process string")
                              (("output" #\o) :type string :optional t :documentation "Output file; if this option is missing, standard output is used")
                              (("help" #\h) :type boolean :optional t :documentation "Display this help and exit")))

(defun main (argv)
  (handler-case
    (macrolet ((ret (code)
                 `(return-from main ,code)))
      (let ((options (handler-case
                       (command-line-arguments:process-command-line-options *cli-options* argv)
                       (simple-error (c)
                                     (format *error-output* "~A~%" c)
                                     (command-line-arguments:show-option-help *cli-options* :stream *error-output*)
                                     (ret 1)))))
        (if (getf options :help)
          (command-line-arguments:show-option-help *cli-options* :stream *error-output*)
          (let ((in-file (getf options :file))
                (output-file (getf options :output))
                (input-string (getf options :string))
                (auto-final-sigma-p (not (getf options :auto-final-sigma))))
            (setf in-file (and in-file (merge-pathnames in-file))
                  output-file (and output-file (merge-pathnames output-file)))
            (when (and in-file
                       (not (probe-file in-file)))
              (format *error-output* "File ~A does not exist.~%" in-file)
              (ret 1))
            (macrolet ((with-input-streams (&body body)
                         `(cond (in-file (with-open-file (in in-file :direction :input)
                                           ,@body))
                                (input-string (with-input-from-string (in input-string)
                                                ,@body))
                                (t (let ((in *standard-input*))
                                     ,@body))))
                       (with-output-streams (&body body)
                         `(cond (output-file (with-open-file (out output-file :direction :output :if-exists :supersede)
                                               ,@body))
                                (t (let ((out *standard-output*))
                                     ,@body)))))
              (handler-case
                (with-input-streams
                  (with-output-streams
                    (loop for line = (read-line in nil nil)
                          while line
                          do (write-line (bcgreek:bcgreek-decode line :auto-final-sigma auto-final-sigma-p) out))))
                (file-error (c) (cond ((equal (file-error-pathname c) in-file)
                                       (format *error-output* "Cannot read from ~A.~%" in-file)
                                       (ret 1))
                                      ((equal (file-error-pathname c) output-file)
                                       (format *error-output* "Cannot write to ~A.~%" output-file)
                                       (ret 1)))))))))
      0)
    (simple-error (c) (format *error-output* "~A~%" c) 1)
    #+nil (error () (format *error-output* "Something went wrong.~%") 1)))
